﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Easy.Common.RegisterType
{
    public class RegisterTypeChecker
    {
        StringBuilder errorSb = new StringBuilder();

        public void Check(IList<RegisterTypeInfo> regInfolst)
        {
            var selflst = regInfolst.Where(a => a.BaseType == a.ImplementationType).Select(a => a).ToList();

            var interfaceBaselst = regInfolst
                .Where
                (
                    a => !a.ImplementationType.IsSubclassOf(a.BaseType)
                    && a.BaseType.IsAssignableFrom(a.ImplementationType)
                    && a.BaseType != a.ImplementationType
                )
                .Select(a => a).ToList();

            var parentBaselst = regInfolst
                .Where
                (
                    a => a.ImplementationType.IsSubclassOf(a.BaseType)
                    && a.BaseType.IsAssignableFrom(a.ImplementationType)
                    && a.BaseType != a.ImplementationType
                )
                .Select(a => a).ToList();


            if (selflst.Count + interfaceBaselst.Count + parentBaselst.Count != regInfolst.Count)
            {
                errorSb.AppendLine("参数错误：selflst.Count + interfaceBaselst.Count + parentBaselst.Count != regInfolst.Count");
            }


            ForeachCheckSelf(selflst, interfaceBaselst, parentBaselst);

            ForeachCheckParentBase(parentBaselst, interfaceBaselst);

            ForeachCheckInterface(interfaceBaselst);

            if (errorSb.Length > 0)
            {
                throw new ArgumentException(errorSb.ToString());
            }
        }




        private void ForeachCheckSelf(List<RegisterTypeInfo> selflst, List<RegisterTypeInfo> interfaceBaselst, List<RegisterTypeInfo> parentBaselst)
        {
            foreach (var self in selflst)
            {
                var interfaceTemp = interfaceBaselst.Where(a => a.ImplementationType == self.ImplementationType).Select(a => a).ToList();

                var parentBaseTemp = parentBaselst.Where(a => a.ImplementationType == self.ImplementationType).Select(a => a).ToList();

                if (interfaceTemp.Count() == 0 && parentBaseTemp.Count() == 0)
                {
                    CheckSelf(self);
                }
                else if (interfaceTemp.Count() > 0 && parentBaseTemp.Count() == 0)
                {
                    CheckSelfAndInterface(self, interfaceTemp);

                    foreach (var item in interfaceTemp)
                    {
                        interfaceBaselst.Remove(item);
                    }
                }
                else if (interfaceTemp.Count() == 0 && parentBaseTemp.Count() > 0)
                {
                    CheckSelfAndParentBase(self, parentBaseTemp);

                    foreach (var item in parentBaseTemp)
                    {
                        parentBaselst.Remove(item);
                    }
                }
                else if (interfaceTemp.Count() > 0 && parentBaseTemp.Count() > 0)
                {
                    CheckSelfAndInterfaceAndParentBase(self, interfaceTemp, parentBaseTemp);

                    foreach (var item in interfaceTemp)
                    {
                        interfaceBaselst.Remove(item);
                    }

                    foreach (var item in parentBaseTemp)
                    {
                        parentBaselst.Remove(item);
                    }
                }
            }
        }


        private void ForeachCheckParentBase(List<RegisterTypeInfo> parentBaselst, List<RegisterTypeInfo> interfaceBaselst)
        {
            foreach (var parentBase in parentBaselst)
            {
                var interfaceTemp = interfaceBaselst.Where(a => a.ImplementationType == parentBase.ImplementationType).Select(a => a).ToList();

                if (interfaceTemp.Count() == 0)
                {
                    CheckParentBase(parentBase);
                }
                else
                {
                    CheckSelfAndParentForMarshalByRef(parentBase, interfaceTemp);

                    foreach (var item in interfaceTemp)
                    {
                        interfaceBaselst.Remove(item);
                    }
                }
            }
        }


        private void ForeachCheckInterface(List<RegisterTypeInfo> interfaceBaselst)
        {
            foreach (var interfaceBase in interfaceBaselst)
            {
                CheckInterface(interfaceBase);
            }
        }

        
        private void CheckSelf(RegisterTypeInfo self)
        {
            if (self.BaseType.IsMarshalByRef)
            {
                if (self.InterceptorType != InterceptorType.TransparentProxy)
                {
                    errorSb.AppendLine(string.Format("实现 MarshalByRefObject 的类型 '{0}' 应使用的拦截类型为： TransparentProxy", self.BaseType.FullName));
                }
            }
            else
            {
                if (self.InterceptorType != InterceptorType.None)
                {
                    errorSb.AppendLine(string.Format("类型 '{0}' 应使用拦截类型为： '{1}'，若要进行拦截，需继承 MarshalByRefObject", self.BaseType.FullName, "None"));
                }
            }
        }

        private void CheckInterface(RegisterTypeInfo interfaceBase)
        {
            if (interfaceBase.BaseType.IsMarshalByRef)
            {
                if (interfaceBase.InterceptorType != InterceptorType.TransparentProxy)
                {
                    errorSb.AppendLine(string.Format("实现 MarshalByRefObject 的类型 '{0}' 应使用的拦截类型为： TransparentProxy", interfaceBase.BaseType.FullName));
                }
            }
            else
            {
                if (interfaceBase.InterceptorType != InterceptorType.Interface
                    && interfaceBase.InterceptorType != InterceptorType.None)
                {
                    errorSb.AppendLine(string.Format("类型 '{0}' 应使用拦截类型为： '{1}'", interfaceBase.BaseType.FullName, "Interface"));
                }
            }
        }

        private void CheckParentBase(RegisterTypeInfo parentBase)
        {
            if (parentBase.BaseType.IsMarshalByRef)
            {
                if (parentBase.InterceptorType != InterceptorType.TransparentProxy)
                {
                    errorSb.AppendLine(string.Format("实现 MarshalByRefObject 的类型 '{0}' 应使用的拦截类型为： TransparentProxy", parentBase.BaseType.FullName));
                }
            }
            else
            {
                if (parentBase.InterceptorType != InterceptorType.VirtualMethod
                    && parentBase.InterceptorType != InterceptorType.None)
                {
                    errorSb.AppendLine(string.Format("类型 '{0}' 应使用拦截类型为： '{1}'", parentBase.BaseType.FullName, "VirtualMethod"));
                }
            }
        }


        private void CheckSelfAndInterface(RegisterTypeInfo self, List<RegisterTypeInfo> interfaceTemp)
        {
            if (self.BaseType.IsMarshalByRef)
            {
                CheckSelfAndParentForMarshalByRef(self, interfaceTemp);
            }
            else
            {
                var parentNames = interfaceTemp.Where(a => a.ImplementationType == self.ImplementationType
                                            && a.InterceptorType != InterceptorType.None)
                                            .Select(a => a.BaseType.FullName);

                if (!(self.InterceptorType == InterceptorType.None && parentNames.Count() == 0))
                {
                    errorSb.AppendLine(string.Format("类型 '{0}{1}' 应使用拦截类型为： '{2}'，若要进行拦截，需继承 MarshalByRefObject", self.BaseType.FullName, string.Join(",", parentNames), "None"));
                }
            }
        }

        private void CheckSelfAndParentBase(RegisterTypeInfo self, List<RegisterTypeInfo> parentBaseTemp)
        {
            if (self.BaseType.IsMarshalByRef)
            {
                CheckSelfAndParentForMarshalByRef(self, parentBaseTemp);
            }
            else
            {
                var parentNames = parentBaseTemp.Where(a => a.ImplementationType == self.ImplementationType
                                            && a.InterceptorType != InterceptorType.None
                                            || a.InterceptorType != InterceptorType.VirtualMethod)
                                            .Select(a => a.BaseType.FullName);

                if (!(self.InterceptorType == InterceptorType.None && parentNames.Count() == 0))
                {
                    errorSb.AppendLine(string.Format("类型 '{0}'和'{1}' 应使用拦截类型为： '{2}' 和 '{3}'", self.BaseType.FullName, string.Join(",", parentNames), "None", "None 或 VirtualMethod"));
                }
            }
        }

        private void CheckSelfAndInterfaceAndParentBase(RegisterTypeInfo self, List<RegisterTypeInfo> interfaceTemp, List<RegisterTypeInfo> parentBaseTemp)
        {
            if (self.BaseType.IsMarshalByRef)
            {
                var templst = interfaceTemp.ToList();
                templst.AddRange(interfaceTemp.ToList());

                CheckSelfAndParentForMarshalByRef(self, templst);
            }
            else
            {
                var parentNames = interfaceTemp.Where(a => a.ImplementationType == self.ImplementationType
                                        && a.InterceptorType != InterceptorType.None)
                                        .Select(a => a.BaseType.FullName).ToList();

                parentNames.AddRange(parentBaseTemp.Where(a => a.ImplementationType == self.ImplementationType
                                        && a.InterceptorType != InterceptorType.None
                                        || a.InterceptorType != InterceptorType.VirtualMethod)
                                        .Select(a => a.BaseType.FullName).ToList());

                if (!(self.InterceptorType == InterceptorType.None && parentNames.Count() == 0))
                {
                    errorSb.AppendLine(string.Format("类型 '{0}'和'{1}' 应使用拦截类型为： '{2}' 和 '{3}'", self.BaseType.FullName, string.Join(",", parentNames), "None", "None 或 VirtualMethod"));
                }
            }
        }

        private void CheckSelfAndParentForMarshalByRef(RegisterTypeInfo self, List<RegisterTypeInfo> parentTypes)
        {
            if (self.InterceptorType == InterceptorType.TransparentProxy)
            {
                var parentNames = parentTypes.Where(a => a.ImplementationType == self.ImplementationType
                                    && a.InterceptorType != InterceptorType.None)
                                    .Select(a => a.BaseType.FullName);

                if (parentNames.Count() > 0)
                {
                    errorSb.AppendLine(string.Format("实现 MarshalByRefObject 的类型 '{0}' 已使用了拦截类型： TransparentProxy，对应的父类或接口不应再次配置拦截，否则将导致重复拦截！ 父类或接口名称：{1}", self.BaseType.FullName, string.Join(",", parentNames)));
                }
            }
            else
            {
                var parentNames = parentTypes.Where(a => a.ImplementationType == self.ImplementationType
                                && a.InterceptorType == InterceptorType.TransparentProxy)
                                .Select(a => a.BaseType.FullName);

                if (parentNames.Count() != 1)
                {
                    errorSb.AppendLine(string.Format("实现 MarshalByRefObject 的类型 '{0}' 应使用的拦截类型为： TransparentProxy，并且只能配置一个TransparentProxy，否则将导致重复拦截！ 父类或接口名称：{1}", self.BaseType.FullName, string.Join(",", parentNames)));
                }
            }
        }
    }
}
